package by.grsu.crs.dao;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import by.grsu.crs.dao.impl.CarDaoImpl;
import by.grsu.crs.dao.impl.ConfidentialDataDaoImpl;
import by.grsu.crs.dao.impl.OrderDaoImpl;
import by.grsu.crs.dao.impl.PaymentDaoImpl;
import by.grsu.crs.dao.impl.StatusDaoImpl;
import by.grsu.crs.dao.impl.UserDaoImpl;

public class DaoManager {
	protected DataSource dataSource = null;
	protected Connection dbConnection = null;
	
	protected UserDao userDao = null;
	protected CarDao carDao = null;
	protected ConfidentialDataDao confidentialDataDao = null;
	protected OrderDao orderDao = null;
	protected PaymentDao paymentDao = null;
	protected StatusDao statusDao = null;
	
	public DaoManager(Connection dbConnection) {
		this.dbConnection = dbConnection;
	}

	protected Connection getDBConnection() throws SQLException {
		if(this.dbConnection == null) {
			this.dbConnection = dataSource.getConnection();
		}		
		return this.dbConnection;
	}

	protected Connection getTxConnection() throws SQLException {
		getDBConnection().setAutoCommit(false);
		return this.dbConnection;
	}

	public Object transaction(DaoCommand command) throws SQLException {
		Object returnValue = null;
		
		try {
			returnValue = command.execute(this);
			getDBConnection().commit();
	    } catch(Exception e) {
	    	getDBConnection().rollback();
	    	//TODO: log this
			e.printStackTrace();
	    } finally {
	    	getDBConnection().setAutoCommit(true);
	    }
		
		return returnValue;
	}

	public Object executeAndClose(DaoCommand command) throws SQLException {
		try {
			return command.execute(this);
		} finally {
			getDBConnection().close();
		}
	}

	public Object transactionAndClose(final DaoCommand command) throws SQLException {
		return executeAndClose(new DaoCommand() {
			public Object execute(DaoManager manager) throws SQLException {
				return manager.transaction(command);
			}
		});
	}
	
	public UserDao getUserDao() {
		if(this.userDao == null) {
			this.userDao = new UserDaoImpl(this.dbConnection);
		}
		return this.userDao;
	}
	
	public UserDao getUserDaoTx() throws SQLException {
		if(this.userDao == null) {
			this.userDao = new UserDaoImpl(getTxConnection());
		}
		return this.userDao;
	}
	
	public CarDao getCarDao() {
		if(this.carDao == null) {
			this.carDao = new CarDaoImpl(this.dbConnection);
		}
		return this.carDao;
	}
	
	public CarDao getCarDaoTx() throws SQLException {
		if(this.carDao == null) {
			this.carDao = new CarDaoImpl(getTxConnection());
		}
		return this.carDao;
	}
	
	public ConfidentialDataDao getConfidentialDataDao() {
		if(this.confidentialDataDao == null) {
			this.confidentialDataDao = new ConfidentialDataDaoImpl(this.dbConnection);
		}
		return this.confidentialDataDao;
	}
	
	public ConfidentialDataDao getConfidentialDataDaoTx() throws SQLException {
		if(this.confidentialDataDao == null) {
			this.confidentialDataDao = new ConfidentialDataDaoImpl(getTxConnection());
		}
		return this.confidentialDataDao;
	}
	
	public OrderDao getOrderDao() {
		if(this.orderDao == null) {
			this.orderDao = new OrderDaoImpl(this.dbConnection);
		}
		return this.orderDao;
	}
	
	public OrderDao getOrderDaoTx() throws SQLException {
		if(this.orderDao == null) {
			this.orderDao = new OrderDaoImpl(getTxConnection());
		}
		return this.orderDao;
	}
	
	public PaymentDao getPaymentDao() {
		if(this.paymentDao == null) {
			this.paymentDao = new PaymentDaoImpl(this.dbConnection);
		}
		return this.paymentDao;
	}
	
	public PaymentDao getPaymentDaoTx() throws SQLException {
		if(this.paymentDao == null) {
			this.paymentDao = new PaymentDaoImpl(getTxConnection());
		}
		return this.paymentDao;
	}
	
	public StatusDao getStatusDao() {
		if(this.statusDao == null) {
			this.statusDao = new StatusDaoImpl(this.dbConnection);
		}
		return this.statusDao;
	}
	
	public StatusDao getStatusDaoTx() throws SQLException {
		if(this.statusDao == null) {
			this.statusDao = new StatusDaoImpl(getTxConnection());
		}
		return this.statusDao;
	}
}
